home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Graphics Plus
/
Graphics Plus.iso
/
msdos
/
plotting
/
pcgplots
/
cgmdispl.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-24
|
31KB
|
1,043 lines
// C++ file for base display classes
// copyright 1992 Pittsburgh Supercomputing Center
// these will only be called if the actual display used doesn't have its own
#include <math.h>
#include "cgm.h"
#ifdef __MSDOS__
#include "cgmdisp.h"
#else
#include "cgmdisplay.h"
#endif
#include "hload1.h"
// error call
extern void myError(const char *inMsg, const char *inMsg2=NULL,
int severity=1);
////
// angle
////
const double angle::tanMax = 1e10; // maximum tangent value
#ifdef macintosh
#pragma segment DIS1
#endif
////
// hershey font stuff
////
// hershey character
////
const int hersheyChar::maxOffset = sizeof(hf_array);
hersheyChar::hersheyChar(const genText *inText, int charNo, int fontNo)
{
static const vdcPts *usePos = NULL;
int offset, i;
next = NULL;
contents = NULL;
if (!inText || (charNo > inText->size())) return; // safety check
////
if (fontNo >= NO_HF) fontNo = 0; // existing font
int wantChar = inText->contents()[charNo]; // character we want
if ((wantChar < 0) || (wantChar >= MAX_HCHARS) ||
((offset = h_array[fontNo][wantChar]) < 0) ||
(offset > maxOffset)) return; // no legal character
// if (hf_array[offset] < 0) return; // no such character in this font
float charSize = inText->info()->height() / 24; // 24 pixel square
// do we have any rotation ?
angle upVec(1, 0), baseVec(0, 1);
if (inText->info()->orientation()) {
upVec = angle(inText->info()->orientation()->y(0),
inText->info()->orientation()->x(0));
baseVec = angle(inText->info()->orientation()->y(1),
inText->info()->orientation()->x(1));
}
////
// now we know we have some points
if (inText->pos()) usePos = inText->pos(); // may be appended
if (!usePos) return; // no where to put it
// figure out the shifts
unsigned char *hPtr = hf_array + offset;
float temp1 = charSize * (128 - (int) hPtr[0]);
float temp2 = charSize * ((int) hPtr[1] - 128);
myShift1 = temp1 * baseVec.cos();
myShift2 = temp2 * baseVec.cos();
myShiftY1 = temp1 * baseVec.sin();
myShiftY2 = temp2 * baseVec.sin();
myHeight = myDepth = 0;
// step over widths
hPtr +=2;
// prepare for loop
int noPts = 0;
float fx, fy;
do {
if (!hPtr[2*noPts] && (!hPtr[2*noPts+1] || (hPtr[2*noPts+1] == 128))) {
// pen coming up or end of character description
if (noPts) { // some to do
if (usePos->type()) { // real vdc's
float *newFloat = new float[noPts * 2];
for (i=0; i<noPts; ++i) {
fx = hPtr[2*i];
fx -= 128;
fx *= charSize;
fy = - (int) hPtr[2*i+1];
fy += 140; // + 12 for bottom of box
fy *= charSize;
if (fy > myHeight) myHeight = fy;
if (-fy > myDepth) myDepth = -fy;
newFloat[2*i] = fx * baseVec.cos() + fy * upVec.cos();
newFloat[2*i+1] = fy * upVec.sin() + fx * baseVec.sin();
}
addPts(new vdcPts(newFloat, noPts));
} else { // integer vdc's
int *newInt = new int[noPts * 2];
for (i=0; i<noPts; ++i) {
fx = hPtr[2*i];
fx -= 128;
fx *= charSize;
fy = - (int) hPtr[2*i+1];
fy += 140; // + 12 for bottom of box
fy *= charSize;
if (fy > myHeight) myHeight = fy;
if (-fy > myDepth) myDepth = -fy;
newInt[2*i] = (int) (fx * baseVec.cos() + fy * upVec.cos());
newInt[2*i+1] = (int) (fy * upVec.sin() + fx * baseVec.sin());
}
addPts(new vdcPts(newInt, noPts));
}
}
if (hPtr[2*noPts+1]) { // more to come
hPtr += noPts * 2 + 2; // step over description
noPts = 0; // start fresh
} else break; // last polyline
} else ++noPts; // normal point
} while ((hPtr + noPts * 2) <= (hf_array + maxOffset)); // in legal position
}
////
// destructor
////
hersheyChar::~hersheyChar()
{
vdcPts *myPtr, *nextPtr;
for (myPtr = contents; myPtr; myPtr = nextPtr) {
nextPtr = myPtr->next;
delete myPtr;
}
}
////
// scale the character
////
void hersheyChar::scale(float factor)
{
myShift1 *= factor;
myShift2 *= factor;
myShiftY1 *= factor;
myShiftY2 *= factor;
myHeight *= factor;
myDepth *= factor;
for (vdcPts *myPtr = contents; myPtr; myPtr = myPtr->next)
myPtr->scale(factor);
}
////
// add some pts to a single character
////
void hersheyChar::addPts(vdcPts *inPts)
{
if (!contents) contents = inPts;
else {
for (vdcPts *myPtr=contents; myPtr->next; myPtr = myPtr->next);
myPtr->next = inPts;
}
}
////
// display the character
////
int hersheyChar::display(baseDisplay *inDisplay)
{
int ret = 1;
for (vdcPts *myPtr=contents; myPtr; myPtr=myPtr->next) {
ret = ret && inDisplay->polyline(myPtr);
}
return ret;
}
////
// shift the character
////
void hersheyChar::shift(float &xShift, float &yShift)
{
for (vdcPts *myPtr=contents; myPtr; myPtr=myPtr->next) {
myPtr->shift(xShift, yShift);
}
}
////
// hershey string
////
hersheyString::hersheyString(const genText *inText) // constructor
{
static float xStart, yStart;
contents = NULL;
myHeight = myDepth = 0;
////
// create all of the characters
for (int i=0; i<inText->size(); ++i)
addChar(new hersheyChar(inText, i));
////
if (inText->pos()) { // may be appended text
xStart = inText->pos()->x(0);
yStart = inText->pos()->y(0);
}
// is this restricted text ?
const vdc *inW, *inH;
if ((inW = inText->width()) && (inH = inText->height())) {
float inWidth = inW->f();
float inHeight = inH->f();
float h = height();
float d = depth();
float w = width();
if (inText->info()) w *= inText->info()->expan();
if (d > 0) h += d;
if (h && w) {
float xHScale = inWidth / w;
float yHScale = inHeight / h;
float useHScale = (xHScale < yHScale) ? xHScale : yHScale;
scale(useHScale); // scale the string
if (d > 0) yStart += d * useHScale;
}
}
// float yStart1 = yStart;
// now take care of positioning
float trueWidth = width(); // figure out true width of string
if (inText->info()) trueWidth *= inText->info()->expan();
////
if (inText->info()->align()) {
switch(inText->info()->align()->h()) {
case 0:
case 1: break; // ok
case 2: xStart -= 0.5 * trueWidth; break;
case 3: xStart -= trueWidth; break;
case 4: break; // fix later
}
switch(inText->info()->align()->v()) {
case 0: break; // ok
case 1: yStart -= height(); break;
case 2: yStart -= 0.9 * height(); break;
case 3: yStart -= 0.5 * height(); break;
case 4: yStart -= 0.1 * height(); break;
case 5: break;
case 6 : break; // fix later
}
}
switch(inText->info()->path()) {
case 0:
right(inText, xStart, yStart); break;
case 1:
left(inText, xStart, yStart); break;
case 2:
up(inText, xStart, yStart); break;
case 3:
down(inText, xStart, yStart); break;
}
}
////
// string width
////
float hersheyString::width()
{
float w=0;
for (hersheyChar *p=contents; p; p=p->next) w += p->width();
return w;
}
////
// scale the string
////
void hersheyString::scale(float factor)
{
myHeight *= factor;
myDepth *= factor;
for (hersheyChar *p=contents; p; p=p->next) p->scale(factor);
}
////
// destructor
////
hersheyString::~hersheyString()
{
hersheyChar *myPtr, *nextPtr;
for (myPtr = contents; myPtr; myPtr = nextPtr) {
nextPtr = myPtr->next;
delete myPtr;
}
}
////
// write out to the right
////
void hersheyString::right(const genText *inText, float &xStart, float &yStart)
{
angle upVec(1, 0), baseVec(0, 1);
float expand = 1;
if (inText->info()->orientation()) {
upVec = angle(inText->info()->orientation()->y(0),
inText->info()->orientation()->x(0));
baseVec = angle(inText->info()->orientation()->y(1),
inText->info()->orientation()->x(1));
if (upVec.size()) expand = baseVec.size() / upVec.size();
}
expand *= inText->info()->expan();
for (hersheyChar *myPtr=contents; myPtr; myPtr=myPtr->next) {
xStart += myPtr->shift1() * expand;
yStart += myPtr->shiftY1();
myPtr->shift(xStart, yStart);
xStart += myPtr->shift2() * expand;
yStart += myPtr->shiftY2();
}
}
////
// write out to the left
////
void hersheyString::left(const genText *inText, float &xStart, float &yStart)
{
angle upVec(1, 0), baseVec(0, 1);
float expand = 1;
if (inText->info()->orientation()) {
upVec = angle(inText->info()->orientation()->y(0),
inText->info()->orientation()->x(0));
baseVec = angle(inText->info()->orientation()->y(1),
inText->info()->orientation()->x(1));
if (upVec.size()) expand = baseVec.size() / upVec.size();
}
expand *= inText->info()->expan();
for (hersheyChar *myPtr=contents; myPtr; myPtr=myPtr->next) {
xStart -= myPtr->shift2() * expand;
yStart -= myPtr->shiftY2();
myPtr->shift(xStart, yStart);
xStart -= myPtr->shift1() * expand;
yStart -= myPtr->shiftY1();
}
}
////
// write up
////
void hersheyString::up(const genText *inText, float &xStart, float &yStart)
{
float x, expand = 1;
angle upVec(1, 0), baseVec(0, 1);
if (inText->info()->orientation()) {
upVec = angle(inText->info()->orientation()->y(0),
inText->info()->orientation()->x(0));
baseVec = angle(inText->info()->orientation()->y(1),
inText->info()->orientation()->x(1));
if (upVec.size()) expand = baseVec.size() / upVec.size();
}
expand *= inText->info()->expan();
for (hersheyChar *myPtr=contents; myPtr; myPtr=myPtr->next) {
x = xStart + myPtr->shift1() * expand;
myPtr->shift(x, yStart);
yStart += myPtr->height() * upVec.sin();
xStart += myPtr->height() * upVec.cos();
}
}
////
// write down
////
void hersheyString::down(const genText *inText, float &xStart, float &yStart)
{
float x, expand = 1;
angle upVec(1, 0), baseVec(0, 1);
if (inText->info()->orientation()) {
upVec = angle(inText->info()->orientation()->y(0),
inText->info()->orientation()->x(0));
baseVec = angle(inText->info()->orientation()->y(1),
inText->info()->orientation()->x(1));
if (upVec.size()) expand = baseVec.size() / upVec.size();
}
expand *= inText->info()->expan();
for (hersheyChar *myPtr=contents; myPtr; myPtr=myPtr->next) {
x = xStart + myPtr->shift1() * expand;
myPtr->shift(x, yStart);
yStart -= myPtr->height() * upVec.sin();
xStart -= myPtr->height() * upVec.cos();
}
}
void hersheyString::addChar(hersheyChar *inChar)
{
if (!contents) contents = inChar;
else {
for (hersheyChar *myPtr = contents; myPtr->next; myPtr = myPtr->next);
myPtr->next = inChar;
if (inChar->height() > myHeight) myHeight = inChar->height();
if (inChar->depth() > myDepth) myDepth = inChar->depth();
}
}
int hersheyString::display(baseDisplay *inDisplay)
{
int ret = 1;
for (hersheyChar *myPtr=contents; myPtr; myPtr=myPtr->next)
ret = ret && myPtr->display(inDisplay);
return ret;
}
#ifdef macintosh
#pragma segment DIS2
#endif
////
// base display
// constructor
////
baseDisplay::baseDisplay()
{
myPxlExtent = NULL;
}
////
// graphical primitives
////
// disjoint polyline
////
int baseDisplay::disPolyline(const vdcPts *inPts) // emulate with a polyline
// we do the disjoint polyline 2 pairs of points at a time
{
int i, j, ret = 1;
vdcPts *myPts = NULL;
if (inPts->type()) { // real vdc's
float *newFloat = new float[4];
myPts = new vdcPts(newFloat, 2);
for (i=0; (i<inPts->no()) && ret; i +=2) {
for (j=0; j<4; ++j) newFloat[j] = inPts->f(2*i+j);
ret = ret && polyline(myPts);
}
} else { // integer VDC's
int *newInt = new int[4];
myPts = new vdcPts(newInt, 2);
for (i=0; (i<inPts->no()) && ret; i +=2) {
for (j=0; j<4; ++j) newInt[j] = inPts->i(2*i+j);
ret = ret && polyline(myPts);
}
}
delete myPts; // clean up
return ret;
}
////
// polymarker
////
int baseDisplay::polymarker(const vdcPts *inPts) // emulate with disjoint polyline
{
int ret = 1, i, j;
float *newFloat;
int *newInt;
vdcPts *myPts = NULL;
float defSize = 0.01 * vdcHeight; // default size
float markerSize; // marker size we shall use
// simple descriptions of the markers as vectors, normalised to unit size
// note that we call circle routine for a circle (number 4)
const int noMarkers = 6; // for convenience; 4 + circle, 0 is a dummy
// points in descriptions
static const int noPoints[noMarkers] = {0, 2, 4, 6, 0, 4};
// position of descriptions
static const int offsets[noMarkers] = {0, 0, 2, 6, 12, 12};
// descriptions
static float markers[32] = {
0.0, 0.0, 0.0, 0.0, // dot
0.0, 0.5, 0.0, -0.5, 0.5, 0.0, -0.5, 0.0, // plus
0.0, 0.5, 0.0, -0.5, 0.25, 0.433, -0.25, -0.433,
-0.25, 0.433, 0.25, -0.433, // asterisk
0.354, 0.354, -0.354, -0.354,
-0.354, 0.354, 0.354, -0.354}; // cross
////
// figure out the size we shall use,
if (myMarkerSize) { // been told a size
markerSize = myMarkerSize->type() ? // relative size required
myMarkerSize->f() * defSize // else
: myMarkerSize->v()->f(); // absolute size
} else markerSize = defSize; // default
if (myMarkerType == 4) { // use a circle
vdc *radius = NULL;
if (inPts->type()) { // real vdc's
newFloat = new float[2];
radius = new vdc((float) (markerSize/2));
myPts = new vdcPts(newFloat, 1);
for (i=0; i<inPts->no() && ret; ++i) {
newFloat[0] = inPts->fx(i);
newFloat[1] = inPts->fy(i);
ret = ret && circle(myPts, radius, 1);
}
} else { // integer vdc's
newInt = new int[2];
radius = new vdc((int) (markerSize/2));
myPts = new vdcPts(newInt, 1);
for (i=0; i<inPts->no() && ret; ++i) {
newInt[0] = inPts->ix(i);
newInt[1] = inPts->iy(i);
ret = ret && circle(myPts, radius, 1);
}
}
delete myPts;
delete radius;
return ret;
} else if ((myMarkerType > 0) && (myMarkerType < 6)) {
////
// use disjoint polyline
float *floatPtr = markers + 2 * offsets[myMarkerType];
if (inPts->type()) { // real vdc's
newFloat = new float[2 * noPoints[myMarkerType]];
myPts = new vdcPts(newFloat, noPoints[myMarkerType]);
for (i=0; i<inPts->no() && ret; ++i) {
for (j=0; j<noPoints[myMarkerType]; ++j) {
newFloat[2*j] = inPts->fx(i) + markerSize * floatPtr[2*j];
newFloat[2*j+1] = inPts->fy(i) + markerSize * floatPtr[2*j+1];
}
ret = ret && disPolyline(myPts);
}
} else { // integer VDC's
newInt = new int[2 * noPoints[myMarkerType]];
myPts = new vdcPts(newInt, noPoints[myMarkerType]);
for (i=0; i<inPts->no() && ret; ++i) {
for (j=0; j<noPoints[myMarkerType]; ++j) {
newInt[2*j] = inPts->ix(i) + (int) (markerSize * floatPtr[2*j]);
newInt[2*j+1] = inPts->iy(i) + (int) (markerSize * floatPtr[2*j+1]);
}
ret = ret && disPolyline(myPts);
}
}
delete myPts;
} // disjoint polyline emulation
return ret;
}
#ifdef macintosh
#pragma segment DIS3
#endif
////
// text, emulate
////
int baseDisplay::text(const genText *inText)
{
hersheyString *myString = new hersheyString(inText);
int ret = myString->display(this);
delete myString;
return ret;
}
////
// polygon
////
int baseDisplay::polygon(const vdcPts *inPts) // emulate with a polyline
{
int i, ret;
vdcPts *myPts;
if (inPts->type()) { // real vdc's
float *newFloat = new float[2 * (inPts->no() + 1)];
for (i=0; i<2 * inPts->no(); ++i) newFloat[i] = inPts->f(i);
newFloat[i++] = inPts->fx(0); // complete polygon
newFloat[i++] = inPts->fy(0);
myPts = new vdcPts(newFloat, inPts->no() + 1);
} else {
int *newInt = new int[2 * (inPts->no() + 1)];
for (i=0; i<2 * inPts->no(); ++i) newInt[i] = inPts->i(i);
newInt[i++] = inPts->ix(0); // complete polygon
newInt[i++] = inPts->iy(0);
myPts = new vdcPts(newInt, inPts->no() + 1);
}
ret = polyline(myPts);
delete myPts;
return ret;
}
////
// polygon set, emulate with a polygon
////
int baseDisplay::polygonSet(const vdcPts *inPts, const int*)
{
return polygon(inPts);
}
////
// cell array
////
int baseDisplay::cells(const cellArray *inCarray) // emulate with a polygon
{
int ret = (inCarray && inCarray->corners()) ?
rectangle(inCarray->corners()) : 1;
return ret;
}
////
// rectangle
////
int baseDisplay::rectangle(const vdcPts *inPts) // emulate with a polygon
{
const int noIndices = 8;
static const int permute[noIndices] = {0, 1, 0, 3, 2, 3, 2, 1};
if (!inPts || (inPts->no() < 2)) {
myError("too few points in a rectangle");
return 1;
}
int ret, i;
vdcPts *myPts;
if (inPts->type()) { // real vdc's
float *newFloat = new float[noIndices];
for (i=0; i<noIndices; ++i) newFloat[i] = inPts->f(permute[i]);
myPts = new vdcPts(newFloat, noIndices / 2);
} else {
int *newInt = new int[8];
for (i=0; i<noIndices; ++i) newInt[i] = inPts->i(permute[i]);
myPts = new vdcPts(newInt, 4);
}
ret = polygon(myPts);
delete myPts;
return ret;
}
////
// circle
////
int baseDisplay::circle(const vdcPts *centre, const vdc *radius, int lineOnly)
{
////
// get the beginning and ending angles
angle theta0(-0.0001, -1); // -pi - epsilon
angle theta1(0.0001, -1); // -pi + epsilon
// get a new set of points from our emulation routine
vdcPts *myPts = getArc(centre, radius, &theta0, &theta1, 1);
int ret = (lineOnly) ? polyline(myPts) : polygon(myPts);
delete myPts;
return ret;
}
////
// basic elliptical arc routine, defaults to circles
// i.e., if r2 == NULL and rotation == 0 will get a circle
////
vdcPts *baseDisplay::getArc(const vdcPts *centre, const vdc *radius,
const angle *theta0, const angle *theta1,
int closeType, const vdc *r2,
const angle *rotation)
{
// draw a circular arc from theta0 to theta1
// if closeType == 0 then we add a final point at the centre
// if closeType == 1 then we add a final point duplicating the first
int i;
vdcPts *myPts;
#ifdef __MSDOS__
int totalPts = 5000; // maximum no of points
#else
int totalPts = 10000; // maximum no of points
#endif
int noPts = (closeType >= 0) ? totalPts - 1 : totalPts;
////
// need the rotation angle, may be null
double crot = (rotation) ? rotation->cos() : 1;
double srot = (rotation) ? rotation->sin() : 0;
////
// get the starting angle, theta0 - rotation, and finishing angle
angle theta = (rotation) ? *theta0 - *rotation : *theta0;
angle end = (rotation) ? *theta1 - *rotation : *theta1;
////
// now figure out a reasonable stepping angle
angle dtheta(1.0 / (1.0 + getSize(radius)), 1);
////
// get the radii, etc.
float fx, fy;
if (centre->type()) { // real
fx = centre->fx(0);
fy = centre->fy(0);
} else {
fx = centre->ix(0);
fy = centre->iy(0);
}
float fa = radius->f(); // first radius
float fb = (r2) ? r2->f() : fa; // second radius
// note that we make sure coincident start and end -> full circle
if (centre->type()) { // real
float *newFloat = new float[totalPts * 2];
for (i=0; (i<noPts) &&
!(end.within(theta, theta + dtheta) && (i>1)); ++i) {
newFloat[2*i] = fx + fa * theta.cos() * crot -
fb * theta.sin() * srot;
newFloat[2*i+1] = fy + fb * theta.sin() * crot +
fa * theta.cos() * srot;
theta +=dtheta;
}
if (closeType == 0) { // add point at centre
newFloat[2*i] = fx;
newFloat[2*i+1] = fy;
++i;
} else if (closeType == 1) { // close with a chord
newFloat[2*i] = newFloat[0];
newFloat[2*i+1] = newFloat[1];
++i;
}
myPts = new vdcPts(newFloat, i);
} else { // integer
int *newInt = new int[totalPts * 2];
for (i=0; (i<noPts) &&
!(end.within(theta, theta + dtheta) && (i>1)); ++i) {
newInt[2*i] = (int) (fx + fa * theta.cos() * crot -
fb * theta.sin() * srot);
newInt[2*i+1] = (int) (fy + fb * theta.sin() * crot +
fa * theta.cos() * srot);
theta +=dtheta;
}
if (closeType == 0) { // add point at centre
newInt[2*i] = (int) fx;
newInt[2*i+1] = (int) fy;
++i;
} else if (closeType == 1) { // close with a chord
newInt[2*i] = newInt[0];
newInt[2*i+1] = newInt[1];
++i;
}
myPts = new vdcPts(newInt, i);
}
return myPts;
}
////
// circular arc, 3 points, may close
// emulate with a polygon or polyline
// closeType == -1 => no closure
// closeType == 0 => pie
// closeType == 1 => chord
////
int baseDisplay::arc3Pt(const vdcPts *inPts, int closeType)
{
// handy macro
#define SQ(in) ((double) (in) * (in))
float *c = new float[2];
int ret = 1;
if (inPts->no() < 3) return ret; // something strange
////
// first figure out centre, radius and 2 angles from 3 points
// make sure they're not co-linear
float t1 = ((inPts->x(2) - inPts->x(0)) * (inPts->y(1) - inPts->y(0)) -
(inPts->x(1) - inPts->x(0)) * (inPts->y(2) - inPts->y(0))) * 2;
if (t1 == 0) return ret; // co-linear
////
// more temporary variables
float t2 = inPts->x2(1) - inPts->x2(0) + inPts->y2(1) - inPts->y2(0);
float t3 = inPts->x2(2) - inPts->x2(0) + inPts->y2(2) - inPts->y2(0);
////
// now get the center coordinates, x and y
c[0] = ((inPts->y(2) - inPts->y(0)) * t2 -
(inPts->y(1) - inPts->y(0)) * t3) / t1;
c[1] = ((inPts->x(2) - inPts->x(0)) * t2 -
(inPts->x(1) - inPts->x(0)) * t3) / t1;
////
// now the radius
float r = sqrt(SQ(inPts->x(0) - c[0]) + SQ(inPts->y(0) - c[1]));
////
// now the angles
angle theta0(inPts->y(0) - c[1], inPts->x(0) - c[0]);
angle theta1(inPts->y(1) - c[1], inPts->x(1) - c[0]);
angle theta2(inPts->y(2) - c[1], inPts->x(2) - c[0]);
////
// we need to include the middle point between the start and end
angle *start, *end;
if (theta1.within(theta0, theta2)) {
start = &theta0;
end = &theta2;
} else {
start = &theta2;
end = &theta0;
}
////
// prepare for the call to the arc routine
vdcPts centre(c);
vdc radius(r);
////
// make the call
vdcPts *myPts = getArc(¢re, &radius, start, end, closeType);
ret = (closeType >= 0) ? polygon(myPts) : polyline(myPts);
delete myPts;
////
// all done
return ret;
}
////
// circular arc, center, 2 vectors, radius, may close
// emulate with a polygon or polyline
////
int baseDisplay::arcCtr(const vdcPts *inPts, vdc *radius, int closeType)
{
int ret = 1;
if (inPts->no() < 3) return ret; // something strange
////
// first figure out 2 angles from info
angle theta0(inPts->y(1), inPts->x(1));
angle theta1(inPts->y(2), inPts->x(2));
////
// now get the emulated points
vdcPts *myPts = getArc(inPts, radius, &theta0, &theta1, closeType);
ret = (closeType >= 0) ? polygon(myPts) : polyline(myPts);
delete myPts;
////
// all done
return ret;
}
#ifdef macintosh
#pragma segment DIS4
#endif
////
// ellipse, 3 pts (centre and 2 CDP's)
// emulate with a polygon
////
int baseDisplay::ellipse(const vdcPts *inPts)
{
if (inPts->no() < 3) return 1; // something strange
vdc *radius1, *radius2;
// get the 2 radii
float r1 = sqrt(SQ(inPts->x(1) - inPts->x(0)) +
SQ(inPts->y(1) - inPts->y(0)));
float r2 = sqrt(SQ(inPts->x(2) - inPts->x(0)) +
SQ(inPts->y(2) - inPts->y(0)));
////
// get the beginning and ending angles
angle theta0(-0.001, -1); // -pi - epsilon
angle theta1(0.001, -1); // -pi + epsilon
// figure out the angle of rotation
angle rotation(inPts->y(1) - inPts->y(0), inPts->x(1) - inPts->x(0));
if (inPts->type()) { // real vdc's
radius1 = new vdc(r1);
radius2 = new vdc(r2);
} else { // integer
radius1 = new vdc((int) r1);
radius2 = new vdc((int) r2);
}
// get a new set of points from our emulation routine
vdcPts *myPts = getArc(inPts, radius1, &theta0, &theta1,
-1, radius2, &rotation);
int ret = polygon(myPts); // do a polygon
delete myPts;
delete radius1;
delete radius2;
return ret;
}
////
// elliptical arc, 5 pts plus close type
// emulate with a polygon or polyline
////
int baseDisplay::ellipArc(const vdcPts *inPts, int closeType)
{
if (inPts->no() < 5) return 1; // something strange
vdc *radius1, *radius2;
// get the 2 radii
float r1 = sqrt(SQ(inPts->x(1) - inPts->x(0)) +
SQ(inPts->y(1) - inPts->y(0)));
float r2 = sqrt(SQ(inPts->x(2) - inPts->x(0)) +
SQ(inPts->y(2) - inPts->y(0)));
////
// figure out the angle of rotation
angle rotation(inPts->y(1) - inPts->y(0), inPts->x(1) - inPts->x(0));
////
// get the starting and ending angles
angle theta0(inPts->y(3), inPts->x(3));
angle theta1(inPts->y(4), inPts->x(4));
if (inPts->type()) { // real vdc's
radius1 = new vdc(r1);
radius2 = new vdc(r2);
} else { // integer
radius1 = new vdc((int) r1);
radius2 = new vdc((int) r2);
}
// get a new set of points from our emulation routine
vdcPts *myPts = getArc(inPts, radius1, &theta0, &theta1,
closeType, radius2, &rotation);
int ret = (closeType >= 0) ? polygon(myPts) : polyline(myPts);
delete myPts;
delete radius1;
delete radius2;
return ret;
}
////
// function called at beginning of each new picture
///
void baseDisplay::newPic()
{
//
// reset defaults
// control elements
//
myTrans = 1;
myClipRect = NULL;
myClip = 0; // fix later
// attributes
myLineIndex = 1;
myLineType = 1;
myLineWidth = NULL;
myMarkerIndex = 1;
myMarkerType = 3;
myMarkerSize = NULL;
myTextIndex = 1;
myFontIndex = 1;
myTextPrec = 0;
myCharExpan = 1.0;
myCharSpace = 0;
myCharHeight = NULL;
myCharOri = NULL;
myTextPath = 0;
myTextAlign = NULL;
myEdgeIndex = 1;
myEdgeType = 1;
myEdgeWidth = NULL;
myCharSetIndex = 1;
myAltCharSetIndex = 1;
myFillIndex = 1;
myIntStyle = 0;
myHatchIndex = 1;
myPatIndex = 1;
myEdgeVis = 0;
myFillRefPt = NULL;
}
////
// function called at beginning of each new picture body
///
void baseDisplay::newPicBody(float inWidth, float inHeight,
float xOff, float yOff)
{
// store the vdc extent
vdcWidth = inWidth;
vdcHeight = inHeight;
// get the extent of the output device
devWidth = pxlExtent()->width();
devHeight = pxlExtent()->height();
// how much do we have to scale ? (take care of non-square pixels later)
xScale = devWidth / vdcWidth;
yScale = devHeight / vdcHeight;
// use the smaller scale (largest enclosed rectangle)
useScale = (yScale < xScale) ? yScale : xScale;
// get the offsets
useOff[0] = pxlExtent()->x(0);
useOff[1] = pxlExtent()->y(0);
// need to keep these separate for inverting devices
useOff[2] = xOff * useScale;
useOff[3] = yOff * useScale;
}
////
// get scaled points into integer form
////
int baseDisplay::getPts(const vdcPts *inPts, int* &outPtr, int close)
{
int i;
// get the memory
outPtr = close ? new int[inPts->no() * 2 + 2] : new int[inPts->no() * 2];
// move over the scaled points
if (inPts->type()) { // real vdc's
if (invert()) { // need to invert the picture
for (i=0; i<inPts->no(); ++i) {
outPtr[2*i] = (int) (useOff[0] + useOff[2] + useScale * inPts->fx(i));
outPtr[2*i+1] = (int) (devHeight + useOff[3]
- useOff[1] - useScale * inPts->fy(i));
}
} else { // normal picture
for (i=0; i<2*inPts->no(); ++i)
outPtr[i] = (int) (useOff[i % 2] + useOff[2 + (i % 2)]
+ useScale * inPts->f(i));
}
} else { // integer VDC's
if (invert()) { // need to invert the picture
for (i=0; i<inPts->no(); ++i) {
outPtr[2*i] = (int) (useOff[0] + useOff[2] + useScale * inPts->ix(i));
outPtr[2*i+1] = (int) (devHeight - useOff[1]
+ useOff[3] - useScale * inPts->iy(i));
}
} else { // normal picture
for (i=0; i<2*inPts->no(); ++i)
outPtr[i] = (int) (useOff[i % 2] + + useOff[2 + (i % 2)]
+ useScale * inPts->i(i));
}
}
if (close) { // want to close the path
outPtr[2 * inPts->no()] = outPtr[0];
outPtr[2 * inPts->no() + 1] = outPtr[1];
}
return 1;
}
////
// get scaled points into float form
////
int baseDisplay::getPts(const vdcPts *inPts, float* &outPtr, int close)
{
int i;
// get the memory
outPtr = close ? new float[inPts->no() * 2 + 2] : new float[inPts->no() * 2];
// move over the scaled points
if (inPts->type()) { // real vdc's
if (invert()) { // need to invert the picture
for (i=0; i<inPts->no(); ++i) {
outPtr[2*i] = useOff[0] + useOff[2] + useScale * inPts->fx(i);
outPtr[2*i+1] = devHeight - useOff[1] + useOff[3]
- useScale * inPts->fy(i);
}
} else { // normal picture
for (i=0; i<2*inPts->no(); ++i)
outPtr[i] = useOff[i % 2] + useOff[2 + (i % 2)]
+ useScale * inPts->f(i);
}
} else { // integer VDC's
if (invert()) { // need to invert the picture
for (i=0; i<inPts->no(); ++i) {
outPtr[2*i] = useOff[0] + useOff[2] + useScale * inPts->ix(i);
outPtr[2*i+1] = devHeight - useOff[1] + useOff[3]
- useScale * inPts->iy(i);
}
} else { // normal picture
for (i=0; i<2*inPts->no(); ++i)
outPtr[i] = useOff[i % 2] + useOff[2 + (i % 2)]
+ useScale * inPts->i(i);
}
}
if (close) { // want to close the path
outPtr[2 * inPts->no()] = outPtr[0];
outPtr[2 * inPts->no() + 1] = outPtr[1];
}
return 1;
}
////
// get scaled points into short form
////
int baseDisplay::getPts(const vdcPts *inPts, short* &outPtr, int close)
{
int i;
// get the memory
outPtr = (close) ? new short[inPts->no() * 2 + 2]
: new short[inPts->no() * 2];
// move over the scaled points
if (inPts->type()) { // real vdc's
if (invert()) { // need to invert the picture
for (i=0; i<inPts->no(); ++i) {
outPtr[2*i] = (short) (useOff[0] + useOff[2] +
useScale * inPts->fx(i));
outPtr[2*i+1] = (short)(devHeight - useOff[1] + useOff[3]
-useScale * inPts->fy(i));
}
} else { // normal picture
for (i=0; i<2*inPts->no(); ++i)
outPtr[i] = (short) (useOff[i % 2] + useOff[2 + (i % 2)]
+ useScale * inPts->f(i));
}
} else { // integer VDC's
if (invert()) { // need to invert the picture
for (i=0; i<inPts->no(); ++i) {
outPtr[2*i] = (short) (useOff[0] + useOff[2] +
useScale * inPts->ix(i));
outPtr[2*i+1] = (short)(devHeight - useOff[1] + useOff[3]
- useScale * inPts->iy(i));
}
} else { // normal picture
for (i=0; i<2*inPts->no(); ++i)
outPtr[i] = (short) (useOff[i % 2] + useOff[2 + (i % 2)]
+ useScale * inPts->i(i));
}
}
if (close) { // want to close the path
outPtr[2 * inPts->no()] = outPtr[0];
outPtr[2 * inPts->no() + 1] = outPtr[1];
}
return 1;
}
////
// attributes
////
void baseDisplay::colrs(const colrTable*) // colour table test implementation
{
// fprintf(stderr, "colour table set\n");
}